package cn.xzc.job.enums;

import cn.xzc.job.annotation.TimerMethod;
import cn.xzc.job.annotation.TimerMethods;
import cn.xzc.job.constant.Constant;
import cn.xzc.job.type.cron.CronExpression;
import cn.xzc.job.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;

/**
 * @author xzc
 * @Classname TimerMethodType
 * @Description 定时任务类型【cron、fixedDelay、fixedRate】
 * @Date 2024/2/19 12:57
 */
public enum TimerMethodType {
    /**
     * 定时任务类型
     */
    CRON, FIXED_DELAY, FIXED_RATE;

    public static TimerMethodType getTimerMethodType(TimerMethod timerMethod) {
        if (errorAnnotation(timerMethod)) {
            return null;
        }
        String cron = timerMethod.cron();
        boolean containCron = StringUtils.isNotBlank(cron) && !Constant.CRON_DISABLED.equals(cron) && validCron(cron);
        boolean containFixedDelay = timerMethod.fixedDelay() > 0;
        boolean containFixedRate = timerMethod.fixedRate() > 0;
        if (containCron && !containFixedDelay && !containFixedRate) {
            return CRON;
        }
        if (!containCron && containFixedDelay && !containFixedRate) {
            return FIXED_DELAY;
        }
        if (!containCron && !containFixedDelay && containFixedRate) {
            return FIXED_RATE;
        }
        return null;
    }

    /**
     * 注解上值至少要有一个
     *
     * @param timerMethod 具体注解
     * @return 具体注解上值判断结果
     */
    public static boolean errorAnnotation(TimerMethod timerMethod) {
        String zone = timerMethod.zone();
        if (StringUtils.isNotBlank(zone)) {
            TimeZone timeZone = TimeZone.getTimeZone(zone);
            if ("GMT".equals(timeZone.getID()) && !zone.startsWith("GMT")) {
                return true;
            }
        }
        String cron = timerMethod.cron();
        //三种定时任务都不存在的情况
        if (StringUtils.isBlank(cron) && timerMethod.fixedDelay() <= 0 && timerMethod.fixedRate() <= 0) {
            return true;
        }
        //定时任务注解上只能有一个定时任务类型生效
        boolean containCron = StringUtils.isNotBlank(cron) && !Constant.CRON_DISABLED.equals(cron) && validCron(cron);
        boolean containFixedDelay = timerMethod.fixedDelay() > 0;
        boolean containFixedRate = timerMethod.fixedRate() > 0;
        if (containCron && !containFixedDelay && !containFixedRate) {
            //判断cron是否有效
            return false;
        }
        if (!containCron && containFixedDelay && !containFixedRate) {
            return false;
        }
        return containCron || containFixedDelay || !containFixedRate;
    }

    /**
     * 校验TimerMethods注解
     *
     * @param timerMethods TimerMethods注解
     * @return 校验TimerMethods注解结果
     */
    public static boolean errorAnnotation(TimerMethods timerMethods) {
        TimerMethod[] value = timerMethods.value();
        if (value.length == 0 || value.length > 3) {
            return true;
        }

        for (TimerMethod timerMethod : value) {
            if (errorAnnotation(timerMethod)) {
                return true;
            }
        }
        //如果存在多个定时任务，则必须是不同类型
        if (value.length > 1) {
            Map<TimerMethodType, Integer> map = new HashMap<>();
            for (TimerMethod timerMethod : value) {
                TimerMethodType timerMethodType = TimerMethodType.getTimerMethodType(timerMethod);
                int count = map.getOrDefault(timerMethodType, 0) + 1;
                //存在重复定时任务类型
                if (count > 1) {
                    return true;
                }
                map.put(timerMethodType, count);
            }
        }
        return false;
    }

    /**
     * 定时任务crontab表达式是否有效
     *
     * @param cron crontab表达式
     * @return 定时任务crontab表达式是否有效
     */
    public static boolean validCron(String cron) {
        try {
            CronExpression.parse(cron);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}
